home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume23 / rc / part01 next >
Encoding:
Text File  |  1991-10-17  |  56.1 KB  |  2,228 lines

  1. Newsgroups: comp.sources.misc
  2. From: byron@archone.tamu.edu (Byron Rakitzis)
  3. Subject:  v23i061:  rc - A Plan 9 shell reimplementation, v1.2, Part01/06
  4. Message-ID: <csm-v23i061=rc.224128@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: a932f2a89d57b43a6a733a0325e502dd
  6. Date: Fri, 18 Oct 1991 03:42:31 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
  10. Posting-number: Volume 23, Issue 61
  11. Archive-name: rc/part01
  12. Environment: UNIX
  13. Supersedes: rc: Volume 20, Issue 10-13
  14.  
  15. This is version 1.2 of the rc shell.  rc is a command interpreter 
  16. and programming language similar to  sh(1).   It is  based on the 
  17. AT&T  plan 9 shell of the same  name.  The shell offers a  C-like 
  18. syntax (much more so than the C shell), and a  powerful mechanism 
  19. for manipulating variables. It is reasonably small and reasonably
  20. fast, especially when compared to contemporary shells. Its use is
  21. intended to be interactive, but the  language  lends  itself well 
  22. to scripts.
  23.  
  24. There's a mailing list for rc at rc@archone.tamu.edu. Send requests 
  25. to be added, etc. to rc-request@archone.tamu.edu.
  26.  
  27. Byron Rakitzis
  28. --------------
  29. #!/bin/sh
  30. # This is a shell archive (produced by shar 3.49)
  31. # To extract the files from this archive, save it to a file, remove
  32. # everything above the "!/bin/sh" line above, and type "sh file_name".
  33. #
  34. # existing files will NOT be overwritten unless -c is specified
  35. #
  36. # This is part 1 of a multipart archive                                    
  37. # do not concatenate these parts, unpack them in order with /bin/sh        
  38. #
  39. # This shar contains:
  40. # length  mode       name
  41. # ------ ---------- ------------------------------------------
  42. #   7545 -rw-r--r-- CHANGES
  43. #   1106 -rw-r--r-- COPYRIGHT
  44. #   5050 -rw-r--r-- EXAMPLES
  45. #   3536 -rw-r--r-- Makefile
  46. #   3366 -rw-r--r-- README
  47. #    408 -rw-r--r-- addon.c
  48. #   1101 -rw-r--r-- addon.h
  49. #  11200 -rw-r--r-- builtins.c
  50. #    191 -rw-r--r-- builtins.h
  51. #   5252 -rw-r--r-- cfix.awk
  52. #    546 -rw-r--r-- config.h
  53. #   2339 -rw-r--r-- except.c
  54. #    310 -rw-r--r-- except.h
  55. #   2671 -rw-r--r-- exec.c
  56. #    104 -rw-r--r-- exec.h
  57. #   2017 -rw-r--r-- execve.c
  58. #   5485 -rw-r--r-- fn.c
  59. #   9420 -rw-r--r-- footobar.c
  60. #    258 -rw-r--r-- footobar.h
  61. #   1619 -rw-r--r-- getopt.c
  62. #     98 -rw-r--r-- getopt.h
  63. #   6378 -rw-r--r-- glob.c
  64. #     66 -rw-r--r-- glob.h
  65. #   9512 -rw-r--r-- glom.c
  66. #    322 -rw-r--r-- glom.h
  67. #   6760 -rw-r--r-- hash.c
  68. #   1313 -rw-r--r-- hash.h
  69. #   3622 -rw-r--r-- heredoc.c
  70. #     97 -rw-r--r-- heredoc.h
  71. #    714 -rw-r--r-- hfix.awk
  72. #   4951 -rw-r--r-- history.1
  73. #   6420 -rw-r--r-- history.c
  74. #   7405 -rw-r--r-- input.c
  75. #    373 -rw-r--r-- input.h
  76. #    209 -rw-r--r-- jbwrap.h
  77. #  10411 -rw-r--r-- lex.c
  78. #    476 -rw-r--r-- lex.h
  79. #    984 -rw-r--r-- list.c
  80. #    119 -rw-r--r-- list.h
  81. #   2703 -rw-r--r-- main.c
  82. #   1992 -rw-r--r-- match.c
  83. #     46 -rw-r--r-- match.h
  84. #   1716 -rw-r--r-- mksignal
  85. #   2229 -rw-r--r-- nalloc.c
  86. #    323 -rw-r--r-- nalloc.h
  87. #    377 -rw-r--r-- node.h
  88. #    772 -rw-r--r-- open.c
  89. #     50 -rw-r--r-- open.h
  90. #     79 -rw-r--r-- parse.h
  91. #   5406 -rw-r--r-- parse.y
  92. #  67056 -rw-r--r-- plan9.ps
  93. #  35457 -rw-r--r-- rc.1
  94. #    654 -rw-r--r-- rc.h
  95. #   2480 -rw-r--r-- redir.c
  96. #     28 -rw-r--r-- redir.h
  97. #   3078 -rw-r--r-- status.c
  98. #    239 -rw-r--r-- status.h
  99. #    766 -rw-r--r-- stddef.h
  100. #    462 -rw-r--r-- stdlib.h
  101. #    516 -rw-r--r-- string.h
  102. #   4722 -rw-r--r-- tree.c
  103. #    132 -rw-r--r-- tree.h
  104. #    759 -rw-r--r-- unistd.h
  105. #   5782 -rw-r--r-- utils.c
  106. #    884 -rw-r--r-- utils.h
  107. #   6567 -rw-r--r-- var.c
  108. #    127 -rw-r--r-- version.c
  109. #   1660 -rw-r--r-- wait.c
  110. #    120 -rw-r--r-- wait.h
  111. #   8100 -rw-r--r-- walk.c
  112. #     59 -rw-r--r-- walk.h
  113. #   2816 -rw-r--r-- which.c
  114. #
  115. if test -r _shar_seq_.tmp; then
  116.     echo 'Must unpack archives in sequence!'
  117.     echo Please unpack part `cat _shar_seq_.tmp` next
  118.     exit 1
  119. fi
  120. # ============= CHANGES ==============
  121. if test -f 'CHANGES' -a X"$1" != X"-c"; then
  122.     echo 'x - skipping CHANGES (File already exists)'
  123.     rm -f _shar_wnt_.tmp
  124. else
  125. > _shar_wnt_.tmp
  126. echo 'x - extracting CHANGES (Text)'
  127. sed 's/^X//' << 'SHAR_EOF' > 'CHANGES' &&
  128. Changes since rc-1.0:
  129. X
  130. builtin now forces a path-search for non-builtin commands. e.g.,
  131. X
  132. X    builtin ls
  133. X
  134. forces a path search for /bin/ls, rather than running a function called
  135. "ls".
  136. X
  137. A bug in the builtin wait was fixed.
  138. X
  139. The builtin whatis how takes a -s flag, for displaying available
  140. signals and their handlers, and also prints correct code for
  141. reinterpretation.  (metacharacters inside variable names were not
  142. correctly quoted)
  143. X
  144. An extra field was added to the "limit" builtin for SunOS systems,
  145. which apparently allow a limit on file descriptors.
  146. X
  147. A home-rolled execve() was written for people with geriatric unices
  148. that don't do #! in the kernel.
  149. X
  150. SIGTERM is now ignored by rc along with SIGQUIT. (This is not how
  151. Duff's shell behaves, but it is standard practise for Unix shells to
  152. ignore SIGTERM)
  153. X
  154. If $history was set to a bad file, then rc would print far too many
  155. error messages.  Now rc prints one error message and assigns null to
  156. $history, if $history names an invalid file.
  157. X
  158. rc now explicitly refuses to trap SIGCLD on System V machines, because
  159. of the weird way in which SIGCLD work. (really because I didn't want to
  160. get into the job control business)
  161. X
  162. A bug was fixed in the parser so that functions with metacharacters in
  163. their names are correctly imported from the environment.
  164. X
  165. he globber was changed to call stat() before calling opendir();
  166. apparently opendir() succeeds on some Unices even when invoked on
  167. regular files.
  168. X
  169. It is now illegal to have '=' be part of a variable name. This should
  170. be the only illegal character inside a variable name!
  171. X
  172. backquote rescanning was rewritten from scratch; now it no longer
  173. assigns null list entries to represent consecutive occurences of $ifs
  174. characters in the input.
  175. X
  176. e.g., now `{echo '   '} returns a null list, and not a 4-element list
  177. of null characters.
  178. X
  179. rc used to export all handlers but those in {sighup, sigint, sigquit,
  180. sigterm, sigexit}.  Now rc does not export ANY signal handlers.
  181. X
  182. rc's lexer was cleaned up to accept 8-bit data. rc is now presumed to
  183. be 8-bit clean.  I would like to hear of evidence to the contrary.
  184. X
  185. rc now traps EOF when scanning a variable name inside a heredoc.
  186. X
  187. rc's fdgchar() was cleaned up so that it did not assign negative values
  188. to unsigned objects.  (this one is truly for the pedants)
  189. X
  190. rc's lexer was fixed so that multiple backslashes at the end of a line
  191. are interpreted correctly.
  192. X
  193. rc's parser now allows a newline to appear after "else" (via
  194. skipnl()).
  195. X
  196. main() was exiting in certain situations with an exit status of 0
  197. instead of rc's real exit status.
  198. X
  199. rc's yacc file was fixed so that yaccs which do "magic" can clean up
  200. after themselves via the tokens YYACCEPT and YYABORT. Most notably,
  201. Sun's yyparse() calls malloc.
  202. X
  203. A mistake in the argument list of treecpy() was cleaned up.
  204. X
  205. Calls to write() are now checked for failure.
  206. X
  207. walk() was optimized for space in two ways: rPIPE was removed and
  208. placed in a separate function body, and a few obvious chances for
  209. employing tail-recursion via goto's was taken. This should result in a
  210. slightly smaller use of stackspace.
  211. X
  212. Additions since 1.1beta:
  213. ------------------------
  214. X
  215. John Mackin kindly supplied a set of awk scripts to convert rc's
  216. source into K&R 1 C. To perform the conversion, type "make C".
  217. X
  218. Paul Haahr and I wrote a history program loosely based upon one
  219. that Boyd Roberts sent to me. Both of these programs are
  220. reimplementations of v8 shell history. Type "make history".
  221. X
  222. Tom Duff has kindly given permission for his paper "rc - a Shell
  223. for Plan 9 and UNIX Systems" to be distributed in PostScript form
  224. with my rc. The file is called "plan9-rc.ps".
  225. X
  226. Changes since 1.1beta:
  227. ----------------------
  228. X
  229. Builtins were changed to flag an error on too many arguments.
  230. Also, the shift builtin now complains if there are no more elements
  231. in $* to shift.
  232. X
  233. The error message printed by exec() ("foo not found") when it could
  234. not find an executable has been updated to read "Permission denied",
  235. and so on.
  236. X
  237. Bugs in the home-rolled execve() were fixed.
  238. X
  239. A compile-time option was added to rc so that rc exports environment
  240. variable names using only the character set [a-zA-Z0-9_]. This is for
  241. braindamaged Bourne shells which don't like characters like - or :
  242. appearing in variable names. rc does this by encoding the variable
  243. name in a hex-based code. It seems to work fine on systems which need
  244. it, but it's definitely a hack.
  245. X
  246. rc now supports /dev/fd, if you have it.
  247. X
  248. Occasionally rc would be too overzealous in its reporting of errors,
  249. so a failed call to write() would cause another failed call to
  250. write() (to print the error!!) and so on... Now rc no longer reports
  251. failed calls to write().
  252. Changes since 1.1gamma:
  253. X
  254. rc sorts the environment strings before exporting them
  255. X
  256. rc ignores signals on rc -c. Fixes the "rc -c sh" followed by an
  257. interrupt bug.
  258. X
  259. the bogus skipnl() action is gone from the parser; the optional
  260. newlines are implemented as yacc productions.
  261. X
  262. a bug in the function-printing code was fixed ( {echo}>file was
  263. exported incorrectly as {echo}>file () ).
  264. X
  265. a=1 {b=2} is now correctly executed as a local assignment to a and a
  266. global assignemnt to b, at the cost of a few extra braces in the
  267. printing of functions.
  268. X
  269. rc's use of jmp_buf was changed to work with braindamaged architectures
  270. which don't define jmp_buf as an array.
  271. X
  272. rc's access() was broken when uid == 0.
  273. X
  274. rc now incorporates switch--case parsing in the grammar; this means
  275. that the rules are a little more strict than they were before, but
  276. reasonable switch() statements should not break.
  277. X
  278. rc -n means don't execute commands, just parse.
  279. X
  280. eval statements now do not reset the line number count in scripts. This
  281. allows for more useful error messages, e.g.,
  282. X
  283. X    line 53: syntax error near end of line
  284. X
  285. as opposed to
  286. X
  287. X    line 1: syntax error near end of line
  288. X
  289. rc's non-exporting of variables like "pid" and "*" has been improved;
  290. it was previously not possible to export a function named "pid" or a
  291. variable named "sigint". This has been fixed.
  292. X
  293. rc's use of wait() was completely revamped. Now FIFOs should be more
  294. reliable, as should be signal handlers.
  295. X
  296. rc -x is now more informative: variable and function assignments are
  297. printed, as are calls to ~.
  298. X
  299. rc -nx now prints the parsetree of each command in addition to refusing
  300. to execute it.
  301. X
  302. for all it's worth, variables named "while" "switch" etc. are now
  303. correctly described by "whatis" (i.e., quoted).
  304. X
  305. for all it's worth, you can now return lists from functions, as long as
  306. each element is a valid exit status (integer, or lowercase signal name
  307. (with or without +core)) The most useful application for this would
  308. be:
  309. X
  310. X    fn foo {
  311. X        stuff
  312. X        stat = $status
  313. X        stuff
  314. X        return $stat
  315. X    }
  316. X
  317. here documents in loops and/or functions now interpret variable
  318. expansions at execute rather than at parse-time.
  319. X
  320. Changes since 1.1gamma:
  321. -----------------------
  322. X
  323. Several bugs were fixed. In particular:
  324. X
  325. When an exception in a braced group occurred, rc did not pop all local
  326. variable definitions.
  327. X
  328. returning from fn prompt would cause an infinite loop.
  329. X
  330. the postfix increment operator used for numbering the /tmp fifos that
  331. rc uses to implement <{} redirection was placed inside a cpp macro
  332. which evaluated an argument twice, and hence all fifos were named after
  333. odd integers. In the interest of fairness to the even integers, this
  334. has been corrected.
  335. X
  336. the man page has been cleaned up in countless ways.
  337. X
  338. rc -nx printed a redundant file-descriptor for "foo<{bar}"
  339. X
  340. "builtin exec sh" did not do the right thing, partly because exec is
  341. not a genuine builtin. However, now it does.
  342. SHAR_EOF
  343. chmod 0644 CHANGES ||
  344. echo 'restore of CHANGES failed'
  345. Wc_c="`wc -c < 'CHANGES'`"
  346. test 7545 -eq "$Wc_c" ||
  347.     echo 'CHANGES: original size 7545, current size' "$Wc_c"
  348. rm -f _shar_wnt_.tmp
  349. fi
  350. # ============= COPYRIGHT ==============
  351. if test -f 'COPYRIGHT' -a X"$1" != X"-c"; then
  352.     echo 'x - skipping COPYRIGHT (File already exists)'
  353.     rm -f _shar_wnt_.tmp
  354. else
  355. > _shar_wnt_.tmp
  356. echo 'x - extracting COPYRIGHT (Text)'
  357. sed 's/^X//' << 'SHAR_EOF' > 'COPYRIGHT' &&
  358. /*
  359. X * Copyright 1991 Byron Rakitzis.  All rights reserved.
  360. X *
  361. X * This software is not subject to any license of the American Telephone
  362. X * and Telegraph Company or of the Regents of the University of California.
  363. X *
  364. X * Permission is granted to anyone to use this software for any purpose on
  365. X * any computer system, and to alter it and redistribute it freely, subject
  366. X * to the following restrictions:
  367. X *
  368. X * 1. The author is not responsible for the consequences of use of this
  369. X *    software, no matter how awful, even if they arise from flaws in it.
  370. X *
  371. X * 2. The origin of this software must not be misrepresented, either by
  372. X *    explicit claim or by omission.  Since few users ever read sources,
  373. X *    credits must appear in the documentation.
  374. X *
  375. X * 3. Altered versions must be plainly marked as such, and must not be
  376. X *    misrepresented as being the original software.  Since few users
  377. X *    ever read sources, credits must appear in the documentation.
  378. X *
  379. X * 4. This notice may not be removed or altered.
  380. X *
  381. X *    [this copyright notice is adapted from Henry Spencer's
  382. X *    "awf" copyright notice.]
  383. X */
  384. SHAR_EOF
  385. chmod 0644 COPYRIGHT ||
  386. echo 'restore of COPYRIGHT failed'
  387. Wc_c="`wc -c < 'COPYRIGHT'`"
  388. test 1106 -eq "$Wc_c" ||
  389.     echo 'COPYRIGHT: original size 1106, current size' "$Wc_c"
  390. rm -f _shar_wnt_.tmp
  391. fi
  392. # ============= EXAMPLES ==============
  393. if test -f 'EXAMPLES' -a X"$1" != X"-c"; then
  394.     echo 'x - skipping EXAMPLES (File already exists)'
  395.     rm -f _shar_wnt_.tmp
  396. else
  397. > _shar_wnt_.tmp
  398. echo 'x - extracting EXAMPLES (Text)'
  399. sed 's/^X//' << 'SHAR_EOF' > 'EXAMPLES' &&
  400. There is no repository for useful rc code snippets as yet, so I'm including
  401. a (short) file in the distribution with some helpful/intriguing pieces of
  402. rc code.
  403. X
  404. A sample .rcrc
  405. --------------
  406. Here is the .rcrc I use on archone:
  407. X
  408. umask 022 
  409. path=(/bin /usr/bin /usr/ucb)
  410. ht=`/usr/arch/bin/hosttype
  411. h=$home
  412. history=$h/.history
  413. bin=$h/bin/$ht
  414. lib=$h/lib/$ht
  415. sh=$h/bin/sh
  416. include=$h/lib/include
  417. X
  418. switch ($ht) {
  419. case sun*
  420. X    OBERON='. '$h/other/oberon
  421. X    p=/usr/ucb
  422. X    compiler='gcc -Wall -O -g'
  423. X    MANPATH=$h/man:/usr/arch/man:/usr/man
  424. X    if (! ~ $TERM ()) {
  425. X        stty dec
  426. X        /usr/arch/bin/msgs -q
  427. X    }
  428. case next
  429. X    p=(/usr/ucb /usr/bin /NextApps)
  430. X    compiler='cc -Wall -O -g -DNODIRENT'
  431. X    MANPATH=$h/man:/usr/arch/man:/usr/man
  432. X    if (! ~ $TERM ())
  433. X        stty dec
  434. case sgi
  435. X    p=(/usr/ucb /usr/sbin /usr/bin)
  436. X    compiler='gcc -Wall -O -g -DNOSIGCLD'
  437. X    MANPATH=$h/man:/usr/arch/man:/usr/catman
  438. X    if (!{~ $TERM () || ~ $TERM *iris*})
  439. X        stty line 1 intr '' erase '' kill ''
  440. case *
  441. X    echo .rcrc not configured for this machine
  442. }
  443. X
  444. path=(. $sh $bin /usr/arch/bin $p /bin /usr/bin/X11 /etc /usr/etc)
  445. cdpath=(. .. $h $h/src $h/misc $h/other $h/adm)
  446. RNINIT=-d$h' -t -M -2400-h -2400+hfrom'; DOTDIR=$h/misc/news
  447. PRINTER=lw
  448. X
  449. fn s {
  450. X    echo $status
  451. }
  452. fn cd {
  453. X    builtin cd $1 && \
  454. X    switch ($1) {
  455. X    case ()
  456. X        dir=$home
  457. X    case *
  458. X        dir=()
  459. X    }
  460. }
  461. fn pwd {
  462. X    if (~ $dir ())
  463. X        dir=`/bin/pwd
  464. X    echo $dir
  465. }
  466. fn x {
  467. X    if (~ `tty /dev/console)
  468. X        clear_colormap
  469. X    clear
  470. X    exit
  471. }
  472. fn p {
  473. X    if (~ $history ()) {
  474. X        echo '$history not set' >[1=2]
  475. X        return 1
  476. X    }
  477. X
  478. X    if (! ~ $#* 0 1 2) {
  479. X        echo usage: $0 '[egrep pattern] [sed command]' >[1=2]
  480. X        return 1
  481. X    }
  482. X
  483. X    command=`{
  484. X        egrep -v '^[     ]*p([     ]+|$)' $history | switch ($#*) {
  485. X        case 0
  486. X            cat
  487. X        case 1
  488. X            egrep $1
  489. X        case 2
  490. X            egrep $1 | sed $2
  491. X        } | tail -1
  492. X    }
  493. X
  494. X    echo $command
  495. X    eval $command
  496. }
  497. X
  498. if (~ $TERM dialup network) {
  499. X    TERM=vt100
  500. X    biff y
  501. }
  502. X
  503. A front-end to NeXT's "openfile"
  504. --------------------------------
  505. X
  506. Named after the sam "B" command for opening a file, this script was written
  507. by Paul Haahr. (Assumes the "pick" command from Kernighan and Pike is also
  508. in your path.)
  509. X
  510. #!/bin/rc
  511. if (~ $#* 0)
  512. X        exec openfile
  513. create = ()
  514. files = ()
  515. for (i in $*)
  516. X        if (test -f $i) {
  517. X                files = ($files $i)
  518. X        } else {
  519. X                create = ($create $i)
  520. X    }
  521. create = `{ pick $create }
  522. files = ($files $create)
  523. for (i in $create)
  524. X        > $i
  525. if (! ~ $#files 0)
  526. X    openfile $files
  527. X
  528. A read function
  529. ---------------
  530. X
  531. Unlike sh, rc doesn't have a read. This clever alternative returns an
  532. exit status as well as fetch a variable. Use as
  533. X
  534. X    read foo
  535. X
  536. to set $foo to a single line from the terminal.
  537. X
  538. (due to John Mackin <john@syd.dit.csiro.au>)
  539. X
  540. fn read {
  541. X        x=() {
  542. X                x = `` ($nl) { awk '{print; print 0; exit}' ^ $nl ^ \
  543. X                                   'END {print 1; print 1}' }
  544. X                $1 = $x(1)
  545. X                return $x(2)
  546. X        }
  547. }
  548. X
  549. XFrom cs.wisc.edu!dws Fri Aug  2 18:16:14 1991
  550. X
  551. #-------
  552. # ls front end
  553. #-------
  554. fn ls    \
  555. {
  556. X    test -t 1 && * = (-FCb $*)
  557. X    builtin ls $*
  558. }
  559. #-------
  560. # nl - holds a newline, useful in certain command substitutions
  561. #-------
  562. nl='
  563. '
  564. #-------
  565. # show - tell me about a name
  566. #
  567. # Runs possibly dangerous things through cat -v in order to protect
  568. # me from the effects of control characters I might have in the
  569. # environment.
  570. #-------
  571. fn show    \
  572. {
  573. X    * = `` $nl {whatis -- $*}
  574. X    for(itis)
  575. X    {
  576. X        switch($^itis)
  577. X        {
  578. X        case 'fn '*    ; echo $itis | cat -v -t
  579. X        case builtin*    ; echo $itis
  580. X        case /*        ; file $itis; ls -ld $itis
  581. X        case *'='*    ; echo $itis | cat -v -t
  582. X        case *        ; echo $itis: UNKNOWN: update show
  583. X        }
  584. X    }
  585. X    itis = ()
  586. }
  587. #-------
  588. # Tell me automatically when a command has a nonzero status.
  589. #-------
  590. fn prompt    \
  591. {
  592. X    Status = $status
  593. X    ~ $Status 0 || echo '[status '$Status']'
  594. }
  595. X
  596. #-------
  597. # chop - echo the given list, less its final member
  598. #
  599. # e.g. chop (a b c) -> (a b)
  600. #-------
  601. fn chop {
  602. X    ~ $#* 0 1 && return 0
  603. X    ans = '' {    # local variable
  604. X        ans = ()
  605. X        while(! ~ $#* 1)
  606. X        {
  607. X            ans = ($ans $1)
  608. X            shift
  609. X        }
  610. X        echo $ans
  611. X    }
  612. }
  613. X
  614. XFrom arnold@audiofax.com Thu May 30 08:49:51 1991
  615. X
  616. # cd.rc --- souped up version of cd
  617. X
  618. # this is designed to emulate the fancy version of cd in ksh,
  619. # so if you're a purist, feel free to gag
  620. X
  621. _cwd=$home
  622. _oldcwd=$home
  623. X
  624. fn cd {
  625. X    if (~ $#* 0) {
  626. X        if (~ $_cwd $home) {    # do nothing
  627. X        } else {
  628. X            builtin cd && { _oldcwd=$_cwd ; _cwd=$home }
  629. X        }
  630. X    } else if (~ $#* 1) {
  631. X        if (~ $1 -) {
  632. X            _t=$_cwd
  633. X            builtin cd $_oldcwd && {
  634. X                _cwd=$_oldcwd
  635. X                _oldcwd=$_t
  636. X                echo $_cwd
  637. X            }
  638. X            _t=()
  639. X        } else {
  640. X            # if a cd happens through the cdpath, rc echos
  641. X            # the directory on its own.  all we have to do
  642. X            # is track where we end up
  643. X            _dopwd = 1
  644. X            { ~ $1 /* } && _dopwd = 0    # absolute path
  645. X            builtin cd $1 && {
  646. X                _oldcwd=$_cwd
  647. X                _cwd=$1
  648. X                { ~ $_dopwd 1 } && _cwd=`/bin/pwd
  649. X            }
  650. X            _dopwd=()
  651. X        }
  652. X    } else if (~ $#* 2) {
  653. X        _t=`{ echo $_cwd | sed 's<'$1'<'$2'<' }
  654. X        builtin cd $_t && {
  655. X            _oldcwd=$_cwd
  656. X            _cwd=$_t
  657. X            echo $_cwd
  658. X        }
  659. X        _t=()
  660. X    } else {
  661. X        echo cd: takes 0, 1, or 2 arguments >[1=2]
  662. X        builtin cd $1 && { _oldcwd=$_cwd ; _cwd=`/bin/pwd ; echo $_cwd }
  663. X    }
  664. }
  665. X
  666. fn pwd { echo $_cwd }
  667. X
  668. SHAR_EOF
  669. chmod 0644 EXAMPLES ||
  670. echo 'restore of EXAMPLES failed'
  671. Wc_c="`wc -c < 'EXAMPLES'`"
  672. test 5050 -eq "$Wc_c" ||
  673.     echo 'EXAMPLES: original size 5050, current size' "$Wc_c"
  674. rm -f _shar_wnt_.tmp
  675. fi
  676. # ============= Makefile ==============
  677. if test -f 'Makefile' -a X"$1" != X"-c"; then
  678.     echo 'x - skipping Makefile (File already exists)'
  679.     rm -f _shar_wnt_.tmp
  680. else
  681. > _shar_wnt_.tmp
  682. echo 'x - extracting Makefile (Text)'
  683. sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
  684. # Makefile for rc.
  685. X
  686. # Check the definitions in stddef.h and the configuration parameters below
  687. # to make sure they are correct for your system.
  688. X
  689. # Configuration parameters for rc:
  690. # Configurations may be added or deleted using ed; e.g., the ed command
  691. # for adding the NODIRENT configuration would be
  692. # /#NODIRENT/s/^.//
  693. #
  694. # Note that config.h automatically sets up configurations for some
  695. # systems.
  696. X
  697. # Define the macro NODIRENT if your system has <sys/dir.h> but not
  698. # <dirent.h>. (e.g., NeXT-OS)
  699. #NODIRENT    = -DNODIRENT
  700. X
  701. # Define the macro DEVFD if your system supports /dev/fd.
  702. #DEVFD        = -DDEVFD
  703. X
  704. # Define the macro NOLIMITS if your system does not support Berkeley
  705. # limits.
  706. #NOLIMITS    = -DNOLIMITS
  707. X
  708. # Define the macro NOSIGCLD if your system uses SIGCLD in the System
  709. # V way. (e.g., Irix)
  710. #NOSIGCLD    = -DNOSIGCLD
  711. X
  712. # Define the macro READLINE if you want rc to call GNU readline
  713. # instead of read(2) on interactive shells.
  714. #READLINE    = -DREADLINE
  715. X
  716. # Define the macro NOEXECVE if your Unix does not interpret #! in the
  717. # kernel, and set EXECVE to execve.o.
  718. #NOEXECVE    = -DNOEXECVE
  719. #EXECVE        = execve.o
  720. X
  721. # Define the macro ADDON if you wish to extend rc via locally-defined
  722. # builtins. An interface is provided in addon.[ch]. Note that the author
  723. # does not endorse any such extensions, rather hopes that this way
  724. # rc will become useful to more people.
  725. #ADDON        = addon.o
  726. X
  727. # If you want rc to default to some interpreter for files which don't
  728. # have a legal #! on the first line, define the macro DEFAULTINTERP.
  729. #DEFAULTINTERP    = -DDEFAULTINTERP=\"/bin/sh\"
  730. X
  731. # If your /bin/sh (or another program you care about) rejects
  732. # environment variables with special characters in them, rc can put
  733. # out ugly variable names using [_0-9a-zA-Z] that encode the real
  734. # name; define PROTECT_ENV for this hack.
  735. #PROTECT_ENV    = -DPROTECT_ENV
  736. X
  737. # If your window system has a broken terminal emulator (and I'm talking
  738. # specifically about the NeXT here) which expects your shell to do csh-
  739. # like job control stuff on startup, define PROTECT_JOB so that rc can
  740. # do the "right" thing.
  741. #PROTECT_JOB    = -DPROTECT_JOB
  742. X
  743. CONFIG = $(NODIRENT) $(NOCMDARG) $(DEVFD) $(NOLIMITS) $(NOSIGCLD) \
  744. X    $(READLINE) $(NOEXECVE)    $(DEFAULTINTERP) $(PROTECT_ENV) $(PROTECT_JOB)
  745. X
  746. # Use an ANSI compiler (or at least one that groks prototypes and void *):
  747. CC=gcc -g -O
  748. CFLAGS=$(CONFIG)
  749. LDFLAGS=
  750. X
  751. # Use bison if you will, but yacc generates a smaller y.tab.c, and the speed
  752. # of the parser is largely irrelevant in a shell.
  753. YACC=yacc
  754. X
  755. OBJS =  $(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \
  756. X    glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o \
  757. X    nalloc.o open.o redir.o sigmsgs.o status.o tree.o utils.o var.o \
  758. X    version.o wait.o walk.o which.o y.tab.o
  759. X
  760. # If rc is compiled with GNU readline, you must supply the correct arguments to
  761. # ld on this line. Typically this would be something like:
  762. #
  763. #    $(CC) -o rc $(OBJS) -lreadline -ltermcap
  764. X
  765. rc: $(OBJS)
  766. X    $(CC) -o rc $(OBJS)
  767. X
  768. sigmsgs.c: mksignal
  769. X    sh mksignal /usr/include/sys/signal.h
  770. X
  771. y.tab.c: parse.y
  772. X    $(YACC) -d parse.y
  773. X
  774. clean:
  775. X    rm -f a.* *.o *.s core *.tab.* *.out
  776. X
  777. history: history.c
  778. X    $(CC) -o ./- history.c
  779. X    rm -f ./-- ./-p ./--p
  780. X    ln -s ./- ./--
  781. X    ln -s ./- ./-p
  782. X    ln -s ./- ./--p
  783. X
  784. C: force
  785. X    -mkdir C
  786. X    for i in *.c; do awk -f cfix.awk $$i >C/$$i; done
  787. X    for i in *.h; do awk -f hfix.awk $$i >C/$$i; done
  788. X    sed 's/CFLAGS=/&-Dconst= /' Makefile > C/Makefile
  789. X    cp mksignal *.y C
  790. X
  791. force:
  792. X
  793. # dependencies:
  794. X
  795. sigmsgs.h: sigmsgs.c
  796. lex.o y.tab.o: y.tab.c
  797. builtins.c fn.c status.c hash.c: sigmsgs.h
  798. SHAR_EOF
  799. chmod 0644 Makefile ||
  800. echo 'restore of Makefile failed'
  801. Wc_c="`wc -c < 'Makefile'`"
  802. test 3536 -eq "$Wc_c" ||
  803.     echo 'Makefile: original size 3536, current size' "$Wc_c"
  804. rm -f _shar_wnt_.tmp
  805. fi
  806. # ============= README ==============
  807. if test -f 'README' -a X"$1" != X"-c"; then
  808.     echo 'x - skipping README (File already exists)'
  809.     rm -f _shar_wnt_.tmp
  810. else
  811. > _shar_wnt_.tmp
  812. echo 'x - extracting README (Text)'
  813. sed 's/^X//' << 'SHAR_EOF' > 'README' &&
  814. This is release 1.2 of rc.
  815. X
  816. Read COPYRIGHT for copying information. All files are
  817. X
  818. Copyright 1991, Byron Rakitzis.
  819. X
  820. COMPILING
  821. X
  822. rc was written in portable ANSI C. For those without gcc or some other
  823. compiler which groks prototypes and (void *), there is a set of awk
  824. scripts which convert the source into old-style C. To do this, type
  825. "make C". This is a nondestructive operation; the new code will be
  826. placed in a subdirectory called "C".
  827. X
  828. Please read the Makefile, and make sure that the configuration parameters
  829. are appropriate for your system. Also, look at config.h and stddef.h.
  830. X
  831. To compile the history program, type "make history". This will create
  832. 1 binary and three soft links pointing at the binary. They are respectively
  833. named -, --, -p and --p.
  834. X
  835. BUGS
  836. X
  837. Send bug reports to byron@archone.tamu.edu. If a core dump is
  838. generated, sending me a backtrace will help me out a great deal. You
  839. can get a backtrace like this:
  840. X
  841. X    ; gdb rc core
  842. X    (gdb) where
  843. X    <<<BACKTRACE INFO>>>
  844. X    (gdb)
  845. X
  846. Also, always report the machine, compiler and OS used to make rc.  It's
  847. possible I may have access to a machine of that type, in which case it
  848. becomes much easier for me to track the bug down.
  849. X
  850. If you are using gcc, please make sure that you have a recent version of
  851. the compiler (1.39 and up) before you send me a note; I have found that
  852. older versions of gcc choke over rc and generate bad code on several
  853. architectures.
  854. X
  855. MAN PAGE
  856. X
  857. The man page works with nroff on my Sun, but I had to use groff in
  858. order to get the man page typeset for a laser printer. I am assuming
  859. that ditroff will also format rc.1 correctly for a printer. If anyone
  860. can tell me how to get BSD troff to do this, I would be grateful.
  861. X
  862. FEEPING CREATURISM
  863. X
  864. See the end of the man page, under "INCOMPATABILITIES" for (known?)
  865. differences from the "real" rc. Most of these changes were necessary
  866. to get rc to work in a reasonable fashion on a real UNIX system; a
  867. few were changes motivated by concern about some inadequacies in
  868. the original design.
  869. X
  870. CREDITS
  871. X
  872. This shell was written by me, Byron Rakitzis, but kudos go to Paul
  873. Haahr for letting me know what a shell should do and for contributing
  874. certain bits and pieces to rc (notably the limits code, most of which.c
  875. and the backquote redirection code), and to Hugh Redelmeier for running
  876. rc through his fussy ANSI compiler and thereby provoking interesting
  877. discussions about portability, and also for providing many valuable
  878. suggestions for improving rc's code in general. Finally, many thanks
  879. go to David Sanderson, for reworking the man page to format well with
  880. troff, and for providing many suggestions both for rc and its man page.
  881. X
  882. Thanks to Boyd Roberts for the original history.c, and to Hugh again
  883. for re-working parts of that code.
  884. X
  885. Of course, without Tom Duff's design of the original rc, I could not
  886. have written this shell (though I probably would have written *a*
  887. shell). Almost of all of the features, with minor exceptions, have been
  888. implemented as described in the Unix v10 manuals. Hats off to td for
  889. designing a C-like, minimal but very useful shell.
  890. X
  891. Tom Duff has kindly given permission for the paper he wrote for UKUUG
  892. to be distributed with this version of rc (called "plan9.ps"). Please
  893. read this paper bearing in mind that it describes a program that was
  894. written at AT&T and that the version of rc presented here differs in some
  895. respects.
  896. SHAR_EOF
  897. chmod 0644 README ||
  898. echo 'restore of README failed'
  899. Wc_c="`wc -c < 'README'`"
  900. test 3366 -eq "$Wc_c" ||
  901.     echo 'README: original size 3366, current size' "$Wc_c"
  902. rm -f _shar_wnt_.tmp
  903. fi
  904. # ============= addon.c ==============
  905. if test -f 'addon.c' -a X"$1" != X"-c"; then
  906.     echo 'x - skipping addon.c (File already exists)'
  907.     rm -f _shar_wnt_.tmp
  908. else
  909. > _shar_wnt_.tmp
  910. echo 'x - extracting addon.c (Text)'
  911. sed 's/^X//' << 'SHAR_EOF' > 'addon.c' &&
  912. /*
  913. X   This file contains the implementations of any locally defined
  914. X   builtins.
  915. */
  916. X
  917. #ifdef    DWS
  918. X
  919. /*
  920. X   This is what DaviD Sanderson (dws@cs.wisc.edu) uses.
  921. */
  922. X
  923. #include <sys/types.h>
  924. #include <sys/file.h>
  925. #include <sys/stat.h>
  926. X
  927. #include "rc.h"        /* for boolean TRUE, FALSE */
  928. #include "status.h"    /* for set() */
  929. #include "addon.h"
  930. #include "utils.h"
  931. X
  932. #include "addon/access.c"
  933. #include "addon/test.c"
  934. X
  935. #endif
  936. SHAR_EOF
  937. chmod 0644 addon.c ||
  938. echo 'restore of addon.c failed'
  939. Wc_c="`wc -c < 'addon.c'`"
  940. test 408 -eq "$Wc_c" ||
  941.     echo 'addon.c: original size 408, current size' "$Wc_c"
  942. rm -f _shar_wnt_.tmp
  943. fi
  944. # ============= addon.h ==============
  945. if test -f 'addon.h' -a X"$1" != X"-c"; then
  946.     echo 'x - skipping addon.h (File already exists)'
  947.     rm -f _shar_wnt_.tmp
  948. else
  949. > _shar_wnt_.tmp
  950. echo 'x - extracting addon.h (Text)'
  951. sed 's/^X//' << 'SHAR_EOF' > 'addon.h' &&
  952. /*
  953. X   This file is the interface to the rest of rc for any locally
  954. X   defined addon builtins.  By default there are none.
  955. X   The interface consists of the following macros.
  956. X  
  957. X   ADDON_FUN    A comma-separated list of the function names for the
  958. X          builtins.
  959. X  
  960. X   ADDON_STR    A comma-separated list of string literals corresponding
  961. X          to the function names in ADDON_FUN.
  962. X  
  963. X   The addon functions must also have proper prototypes in this file.
  964. X   The builtins all have the form:
  965. X  
  966. X      void b_NAME(char **av);
  967. X  
  968. X   Builtins report their exit status using set(TRUE) or set(FALSE).
  969. X  
  970. X   Example:
  971. X  
  972. X      #define ADDON_FUN    b_test, b_printf
  973. X      #define ADDON_STR    "test", "printf"
  974. X      extern void b_test(char **av);
  975. X      extern void b_printf(char **av);
  976. */
  977. X
  978. #define ADDON_FUN    /* no addons by default */
  979. #define ADDON_STR    /* no addons by default */
  980. X
  981. #ifdef    DWS
  982. X
  983. /*
  984. X   This is what DaviD Sanderson (dws@cs.wisc.edu) uses.
  985. */
  986. X
  987. #undef    ADDON_FUN
  988. #define ADDON_FUN    b_access, b_test, b_test
  989. #undef    ADDON_STR
  990. #define ADDON_STR    "access", "test", "["
  991. X
  992. extern void b_access(char **av);
  993. extern void b_test(char **av);
  994. X
  995. #endif
  996. SHAR_EOF
  997. chmod 0644 addon.h ||
  998. echo 'restore of addon.h failed'
  999. Wc_c="`wc -c < 'addon.h'`"
  1000. test 1101 -eq "$Wc_c" ||
  1001.     echo 'addon.h: original size 1101, current size' "$Wc_c"
  1002. rm -f _shar_wnt_.tmp
  1003. fi
  1004. # ============= builtins.c ==============
  1005. if test -f 'builtins.c' -a X"$1" != X"-c"; then
  1006.     echo 'x - skipping builtins.c (File already exists)'
  1007.     rm -f _shar_wnt_.tmp
  1008. else
  1009. > _shar_wnt_.tmp
  1010. echo 'x - extracting builtins.c (Text)'
  1011. sed 's/^X//' << 'SHAR_EOF' > 'builtins.c' &&
  1012. /* builtins.c: the collection of rc's builtin commands */
  1013. X
  1014. /*
  1015. X    NOTE: rc's builtins do not call "rc_error" because they are
  1016. X    commands, and rc errors usually arise from syntax errors. e.g.,
  1017. X    you probably don't want interpretation of a shell script to stop
  1018. X    because of a bad umask.
  1019. */
  1020. X
  1021. #include "jbwrap.h"
  1022. #include <errno.h>
  1023. #include "rc.h"
  1024. #ifndef NOLIMITS
  1025. #include <sys/time.h>
  1026. #include <sys/resource.h>
  1027. #endif
  1028. #include "utils.h"
  1029. #include "walk.h"
  1030. #include "input.h"
  1031. #include "builtins.h"
  1032. #include "hash.h"
  1033. #include "nalloc.h"
  1034. #include "status.h"
  1035. #include "footobar.h"
  1036. #include "lex.h"
  1037. #include "open.h"
  1038. #include "except.h"
  1039. #include "redir.h"
  1040. #include "glom.h"
  1041. #include "tree.h"
  1042. #include "sigmsgs.h"
  1043. #include "getopt.h"
  1044. #include "wait.h"
  1045. #include "addon.h"
  1046. X
  1047. extern int umask(int);
  1048. X
  1049. static void b_break(char **), b_cd(char **),
  1050. X    b_echo(char **), b_eval(char **), b_exit(char **), b_limit(char **),
  1051. X    b_return(char **), b_shift(char **), b_umask(char **), b_wait(char **),
  1052. X    b_whatis(char **);
  1053. X
  1054. static builtin_t *const builtins[] = {
  1055. X    b_break, b_builtin, b_cd, b_echo, b_eval, b_exec, b_exit,
  1056. X    b_limit, b_return, b_shift, b_umask, b_wait, b_whatis, b_dot,
  1057. X    ADDON_FUN
  1058. };
  1059. X
  1060. static char *const builtins_str[] = {
  1061. X    "break", "builtin", "cd", "echo", "eval", "exec", "exit",
  1062. X    "limit", "return", "shift", "umask", "wait", "whatis", ".",
  1063. X    ADDON_STR
  1064. };
  1065. X
  1066. builtin_t *isbuiltin(char *s) {
  1067. X    int i;
  1068. X
  1069. X    for (i = 0; i < arraysize(builtins_str); i++)
  1070. X        if (streq(builtins_str[i], s))
  1071. X            return builtins[i];
  1072. X    return NULL;
  1073. }
  1074. X
  1075. /* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */
  1076. X
  1077. void funcall(char **av) {
  1078. X    jbwrap j;
  1079. X    Estack e1, e2;
  1080. X
  1081. X    if (setjmp(j.j))
  1082. X        return;
  1083. X
  1084. X    starassign(*av, av+1, TRUE);
  1085. X    except(RETURN, &j, &e1);
  1086. X    except(VARSTACK, "*", &e2);
  1087. X    walk(treecpy(fnlookup(*av),nalloc), TRUE);
  1088. X    varrm("*", TRUE);
  1089. X    unexcept(); /* VARSTACK */
  1090. X    unexcept(); /* RETURN */
  1091. }
  1092. X
  1093. static void arg_count(char *name) {
  1094. X    fprint(2, "too many arguments to %s\n", name);
  1095. X    set(FALSE);
  1096. }
  1097. X
  1098. static void badnum(char *num) {
  1099. X    fprint(2, "%s is a bad number", num);
  1100. X    set(FALSE);
  1101. }
  1102. X
  1103. /* a dummy command. (exec() performs "exec" simply by not forking) */
  1104. X
  1105. void b_exec(char **av) {
  1106. }
  1107. X
  1108. /* echo -n omits a newline. echo -- -n echos '-n' */
  1109. X
  1110. static void b_echo(char **av) {
  1111. X    SIZE_T i;
  1112. X    char *format = "%a\n";
  1113. X
  1114. X    if (*++av != NULL) {
  1115. X        if (streq(*av, "-n")) {
  1116. X            format = "%a";
  1117. X            av++;
  1118. X        } else if (streq(*av, "--")) {
  1119. X            av++;
  1120. X        }
  1121. X    }
  1122. X
  1123. X    i = strarraylen(av) + 1; /* one for the null terminator */
  1124. X
  1125. X    if (i < FPRINT_SIZE)
  1126. X        fprint(1, format, av);
  1127. X    else
  1128. X        writeall(1, sprint(nalloc(i), format, av), i-1);
  1129. X    set(TRUE);
  1130. }
  1131. X
  1132. /* cd. traverse $cdpath if the directory given is not an absolute pathname */
  1133. X
  1134. static void b_cd(char **av) {
  1135. X    List *s, nil;
  1136. X    char *path = NULL;
  1137. X    SIZE_T t, pathlen = 0;
  1138. X
  1139. X    if (*++av == NULL) {
  1140. X        s = varlookup("home");
  1141. X        *av = (s == NULL) ? "/" : s->w;
  1142. X    } else if (av[1] != NULL) {
  1143. X        arg_count("cd");
  1144. X        return;
  1145. X    }
  1146. X
  1147. X    if (isabsolute(*av)) { /* absolute pathname? */
  1148. X        if (chdir(*av) < 0) {
  1149. X            set(FALSE);
  1150. X            uerror(*av);
  1151. X        } else
  1152. X            set(TRUE);
  1153. X    } else {
  1154. X        s = varlookup("cdpath");
  1155. X        if (s == NULL) {
  1156. X            s = &nil;
  1157. X            nil.w = "";
  1158. X            nil.n = NULL;
  1159. X        }
  1160. X        do {
  1161. X            if (s != &nil && *s->w != '\0') {
  1162. X                t = strlen(*av) + strlen(s->w) + 2;
  1163. X                if (t > pathlen)
  1164. X                    path = nalloc(pathlen = t);
  1165. X                strcpy(path, s->w);
  1166. X                strcat(path, "/");
  1167. X                strcat(path, *av);
  1168. X            } else {
  1169. X                pathlen = 0;
  1170. X                path = *av;
  1171. X            }
  1172. X            if (chdir(path) >= 0) {
  1173. X                set(TRUE);
  1174. X                if (interactive && *s->w != '\0' && !streq(s->w,"."))
  1175. X                    fprint(1,"%s\n",path);
  1176. X                return;
  1177. X            }
  1178. X            s = s->n;
  1179. X        } while (s != NULL);
  1180. X        fprint(2,"couldn't cd to %s\n", *av);
  1181. X        set(FALSE);
  1182. X    }
  1183. }
  1184. X
  1185. static void b_umask(char **av) {
  1186. X    int i;
  1187. X
  1188. X    if (*++av == NULL) {
  1189. X        set(TRUE);
  1190. X        i = umask(0);
  1191. X        umask(i);
  1192. X        fprint(1, "0%o\n", i);
  1193. X    } else if (av[1] == NULL) {
  1194. X        i = o2u(*av);
  1195. X        if ((unsigned int) i > 0777) {
  1196. X            fprint(2,"bad umask\n");
  1197. X            set(FALSE);
  1198. X        } else {
  1199. X            umask(i);
  1200. X            set(TRUE);
  1201. X        }
  1202. X    } else {
  1203. X        arg_count("umask");
  1204. X        return;
  1205. X    }
  1206. }
  1207. X
  1208. static void b_exit(char **av) {
  1209. X    int s;
  1210. X
  1211. X    if (av[1] == NULL)
  1212. X        rc_exit(getstatus());
  1213. X    if (av[2] != NULL) {
  1214. X        fprint(2, "exit: too many arguments\n");
  1215. X        rc_exit(1);
  1216. X    }
  1217. X    if ((s = a2u(av[1])) >= 0)
  1218. X        rc_exit(s);
  1219. X    badnum(av[1]);
  1220. X    rc_exit(1);
  1221. }
  1222. X
  1223. /* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */
  1224. X
  1225. static void b_return(char **av) {
  1226. X    if (av[1] != NULL)
  1227. X        ssetstatus(av + 1);
  1228. X    rc_raise(RETURN);
  1229. }
  1230. X
  1231. /* raise a "break" exception for breaking out of for and while loops */
  1232. X
  1233. static void b_break(char **av) {
  1234. X    if (av[1] != NULL) {
  1235. X        arg_count("break");
  1236. X        return;
  1237. X    }
  1238. X    rc_raise(BREAK);
  1239. }
  1240. X
  1241. /* shift $* n places (default 1) */
  1242. X
  1243. static void b_shift(char **av) {
  1244. X    int shift;
  1245. X    List *s, *dollarzero;
  1246. X
  1247. X    shift = (av[1] == NULL ? 1 : a2u(av[1]));
  1248. X
  1249. X    if (av[1] != NULL && av[2] != NULL) {
  1250. X        arg_count("shift");
  1251. X        return;
  1252. X    }
  1253. X
  1254. X    if (shift < 0) {
  1255. X        badnum(av[1]);
  1256. X        return;
  1257. X    }
  1258. X
  1259. X    s = varlookup("*")->n;
  1260. X    dollarzero = varlookup("0");
  1261. X
  1262. X    while (s != NULL && shift != 0) {
  1263. X        s = s->n;
  1264. X        --shift;
  1265. X    }
  1266. X
  1267. X    if (s == NULL && shift != 0) {
  1268. X        fprint(2,"cannot shift\n");
  1269. X        set(FALSE);
  1270. X    } else {
  1271. X        varassign("*", append(dollarzero, s), FALSE);
  1272. X        set(TRUE);
  1273. X    }
  1274. }
  1275. X
  1276. /* dud function */
  1277. X
  1278. void b_builtin(char **av) {
  1279. }
  1280. X
  1281. /* wait for a given process, or all outstanding processes */
  1282. X
  1283. static void b_wait(char **av) {
  1284. X    int stat, pid;
  1285. X
  1286. X    if (av[1] == NULL) {
  1287. X        waitforall(&stat);
  1288. X        setstatus(stat);
  1289. X        return;
  1290. X    }
  1291. X
  1292. X    if (av[2] != NULL) {
  1293. X        arg_count("wait");
  1294. X        return;
  1295. X    }
  1296. X
  1297. X    if ((pid = a2u(av[1])) < 0) {
  1298. X        badnum(av[1]);
  1299. X        return;
  1300. X    }
  1301. X
  1302. X    if (rc_wait4(pid, &stat) > 0)
  1303. X        setstatus(stat);
  1304. X    else
  1305. X        set(FALSE);
  1306. }
  1307. X
  1308. /*
  1309. X   whatis without arguments prints all variables and functions. Otherwise, check to see if a name
  1310. X   is defined as a variable, function or pathname.
  1311. */
  1312. X
  1313. static void b_whatis(char **av) {
  1314. X    enum bool f,found;
  1315. X    int i,j,ac,c;
  1316. X    List *s;
  1317. X    Node *n;
  1318. X    char *e;
  1319. X    boolean ess = FALSE;
  1320. X
  1321. X    optind = 0;
  1322. X    for (ac = 0; av[ac] != NULL; ac++)
  1323. X        ; /* count the arguments for getopt */
  1324. X
  1325. X    while ((c = getopt(ac, av, "s")) != -1)
  1326. X        switch (c) {
  1327. X        case 's':
  1328. X            ess = TRUE;
  1329. X            break;
  1330. X        case '?':
  1331. X            set(FALSE);
  1332. X            return;
  1333. X        }
  1334. X
  1335. X    av += optind;
  1336. X
  1337. X    if (*av == NULL && !ess) {
  1338. X        whatare_all_vars();
  1339. X        set(TRUE);
  1340. X        return;
  1341. X    }
  1342. X
  1343. X    if (ess)
  1344. X        whatare_all_signals();
  1345. X
  1346. X    found = TRUE;
  1347. X
  1348. X    for (i = 0; av[i] != NULL; i++) {
  1349. X        f = FALSE;
  1350. X        errno = ENOENT;
  1351. X        if ((s = varlookup(av[i])) != NULL) {
  1352. X            f = TRUE;
  1353. X            prettyprint_var(1, av[i], s);
  1354. X        }
  1355. X        if ((n = fnlookup(av[i])) != NULL) {
  1356. X            f = TRUE;
  1357. X            prettyprint_fn(1, av[i], n);
  1358. X        } else if (isbuiltin(av[i]) != NULL) {
  1359. X            f = TRUE;
  1360. X            for (j = 0; j < arraysize(builtins_str); j++)
  1361. X                if (streq(av[i], builtins_str[j]))
  1362. X                    break;
  1363. X            fprint(1, "builtin %s\n", builtins_str[j]);
  1364. X        } else if ((e = which(av[i], FALSE)) != NULL) {
  1365. X            f = TRUE;
  1366. X            fprint(1, "%s\n", e);
  1367. X        }
  1368. X        if (!f) {
  1369. X            found = FALSE;
  1370. X            if (errno != ENOENT)
  1371. X                uerror(av[i]);
  1372. X            else
  1373. X                fprint(2, "%s not found\n", av[i]);
  1374. X        }
  1375. X    }
  1376. X
  1377. X    set(found);
  1378. }
  1379. X
  1380. /* push a string to be eval'ed onto the input stack. evaluate it */
  1381. X
  1382. static void b_eval(char **av) {
  1383. X    boolean i = interactive;
  1384. X
  1385. X    if (av[1] == NULL)
  1386. X        return;
  1387. X
  1388. X    interactive = FALSE;
  1389. X    pushinput(STRING, av + 1, i); /* don't reset line numbers on noninteractive eval */
  1390. X    doit(TRUE);
  1391. X    interactive = i;
  1392. }
  1393. X
  1394. /*
  1395. X   push a file to be interpreted onto the input stack. with "-i" treat this as an interactive
  1396. X   input source.
  1397. */
  1398. X
  1399. void b_dot(char **av) {
  1400. X    int fd;
  1401. X    boolean old_i = interactive, i = FALSE;
  1402. X    Estack e;
  1403. X
  1404. X    av++;
  1405. X
  1406. X    if (*av == NULL)
  1407. X        return;
  1408. X
  1409. X    if (streq(*av,"-i")) {
  1410. X        av++;
  1411. X        i = TRUE;
  1412. X    }
  1413. X
  1414. X    if (dasheye) { /* rc -i file has to do the right thing. reset the dasheye state to FALSE, though. */
  1415. X        dasheye = FALSE;
  1416. X        i = TRUE;
  1417. X    }
  1418. X
  1419. X    if (*av == NULL)
  1420. X        return;
  1421. X
  1422. X    fd = rc_open(*av, FROM);
  1423. X
  1424. X    if (fd < 0) {
  1425. X        if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */
  1426. X            rcrc = FALSE;
  1427. X        else
  1428. X            uerror(*av);
  1429. X        set(FALSE);
  1430. X        return;
  1431. X    }
  1432. X    rcrc = FALSE;
  1433. X
  1434. X    starassign(*av, av+1, TRUE);
  1435. X    pushinput(FD, fd);
  1436. X    interactive = i;
  1437. X    except(VARSTACK, "*", &e);
  1438. X    doit(TRUE);
  1439. X    varrm("*", TRUE);
  1440. X    unexcept(); /* VARSTACK */
  1441. X    interactive = old_i;
  1442. }
  1443. X
  1444. /* Berkeley limit support was cleaned up by Paul Haahr. */
  1445. X
  1446. #ifdef NOLIMITS
  1447. static void b_limit(char **av) {
  1448. X    rc_error("rc was compiled without berkeley limits");
  1449. }
  1450. #else
  1451. X
  1452. typedef struct Suffix Suffix;
  1453. struct Suffix {
  1454. X    const Suffix *next;
  1455. X    long amount;
  1456. X    char *name;
  1457. };
  1458. X
  1459. static const Suffix
  1460. X    kbsuf = { NULL, 1024, "k" },
  1461. X    mbsuf = { &kbsuf, 1024*1024, "m" },
  1462. X    gbsuf = { &mbsuf, 1024*1024*1024, "g" },
  1463. X    stsuf = { NULL, 1, "s" },
  1464. X    mtsuf = { &stsuf, 60, "m" },
  1465. X    htsuf = { &mtsuf, 60*60, "h" };
  1466. #define    SIZESUF &gbsuf
  1467. #define    TIMESUF &htsuf
  1468. #define    NOSUF ((Suffix *) NULL)  /* for RLIMIT_NOFILE on SunOS 4.1 */
  1469. X
  1470. typedef struct {
  1471. X    char *name;
  1472. X    int flag;
  1473. X    const Suffix *suffix;
  1474. } Limit;
  1475. static const Limit limits[] = {
  1476. X    { "cputime",        RLIMIT_CPU,    TIMESUF },
  1477. X    { "filesize",        RLIMIT_FSIZE,    SIZESUF },
  1478. X    { "datasize",        RLIMIT_DATA,    SIZESUF },
  1479. X    { "stacksize",        RLIMIT_STACK,    SIZESUF },
  1480. X    { "coredumpsize",    RLIMIT_CORE,    SIZESUF },
  1481. #ifdef RLIMIT_RSS /* SysVr4 does not have this */
  1482. X    { "memoryuse",        RLIMIT_RSS,    SIZESUF },
  1483. #endif
  1484. #ifdef RLIMIT_VMEM /* instead, they have this! */
  1485. X    { "vmemory",        RLIMIT_VMEM,    SIZESUF },
  1486. #endif
  1487. #ifdef RLIMIT_NOFILE  /* SunOS 4.1 adds a limit on file descriptors */
  1488. X    { "descriptors",    RLIMIT_NOFILE,    NOSUF },
  1489. #endif
  1490. X    { NULL, 0, NULL }
  1491. };
  1492. X
  1493. extern int getrlimit(int, struct rlimit *);
  1494. extern int setrlimit(int, struct rlimit *);
  1495. X
  1496. static void printlimit(const Limit *limit, boolean hard) {
  1497. X    struct rlimit rlim;
  1498. X    long lim;
  1499. X    getrlimit(limit->flag, &rlim);
  1500. X    if (hard)
  1501. X        lim = rlim.rlim_max;
  1502. X    else
  1503. X        lim = rlim.rlim_cur;
  1504. X    if (lim == RLIM_INFINITY)
  1505. X        fprint(1, "%s \tunlimited\n", limit->name);
  1506. X    else {
  1507. X        const Suffix *suf;
  1508. X        for (suf = limit->suffix; suf != NULL; suf = suf->next)
  1509. X            if (lim % suf->amount == 0) {
  1510. X                lim /= suf->amount;
  1511. X                break;
  1512. X            }
  1513. X        fprint(1, "%s \t%d%s\n", limit->name, lim, suf == NULL ? "" : suf->name);
  1514. X    }
  1515. }
  1516. X
  1517. static long parselimit(const Limit *limit, char *s) {
  1518. X    int len = strlen(s);
  1519. X    long lim = 1;
  1520. X    const Suffix *suf = limit->suffix;
  1521. X    if (streq(s, "unlimited"))
  1522. X        return RLIM_INFINITY;
  1523. X    if (suf == TIMESUF && strchr(s, ':') != NULL) {
  1524. X        char *t = strchr(s, ':');
  1525. X        *t++ = '\0';
  1526. X        lim = 60 * a2u(s) + a2u(t);
  1527. X    } else {
  1528. X        for (; suf != NULL; suf = suf->next)
  1529. X            if (streq(suf->name, s + len - strlen(suf->name))) {
  1530. X                s[len - strlen(suf->name)] = '\0';
  1531. X                lim *= suf->amount;
  1532. X                break;
  1533. X            }
  1534. X        lim *= a2u(s);
  1535. X    }
  1536. X    return lim;
  1537. }
  1538. X
  1539. static void b_limit(char **av) {
  1540. X    const Limit *lp = limits;
  1541. X    boolean hard = FALSE;
  1542. X
  1543. X    if (*++av != NULL && streq(*av, "-h")) {
  1544. X        av++;
  1545. X        hard = TRUE;
  1546. X    }
  1547. X
  1548. X    if (*av == NULL) {
  1549. X        for (; lp->name != NULL; lp++)
  1550. X            printlimit(lp, hard);
  1551. X        return;
  1552. X    }
  1553. X
  1554. X    for (;; lp++) {
  1555. X        if (lp->name == NULL) {
  1556. X            fprint(2,"no such limit\n");
  1557. X            set(FALSE);
  1558. X            return;
  1559. X        }
  1560. X        if (streq(*av, lp->name))
  1561. X            break;
  1562. X    }
  1563. X
  1564. X    if (*++av == NULL)
  1565. X        printlimit(lp, hard);
  1566. X    else {
  1567. X        struct rlimit rlim;
  1568. X        long pl;
  1569. X        getrlimit(lp->flag, &rlim);
  1570. X        if ((pl = parselimit(lp, *av)) < 0) {
  1571. X            fprint(2,"bad limit\n");
  1572. X            set(FALSE);
  1573. X            return;
  1574. X        }
  1575. X        if (hard)
  1576. X            rlim.rlim_max = pl;
  1577. X        else
  1578. X            rlim.rlim_cur = pl;
  1579. X        if (setrlimit(lp->flag, &rlim) == -1) {
  1580. X            uerror("setrlimit");
  1581. X            set(FALSE);
  1582. X        } else
  1583. X            set(TRUE);
  1584. X    }
  1585. }
  1586. #endif
  1587. SHAR_EOF
  1588. chmod 0644 builtins.c ||
  1589. echo 'restore of builtins.c failed'
  1590. Wc_c="`wc -c < 'builtins.c'`"
  1591. test 11200 -eq "$Wc_c" ||
  1592.     echo 'builtins.c: original size 11200, current size' "$Wc_c"
  1593. rm -f _shar_wnt_.tmp
  1594. fi
  1595. # ============= builtins.h ==============
  1596. if test -f 'builtins.h' -a X"$1" != X"-c"; then
  1597.     echo 'x - skipping builtins.h (File already exists)'
  1598.     rm -f _shar_wnt_.tmp
  1599. else
  1600. > _shar_wnt_.tmp
  1601. echo 'x - extracting builtins.h (Text)'
  1602. sed 's/^X//' << 'SHAR_EOF' > 'builtins.h' &&
  1603. typedef void builtin_t(char **);
  1604. X
  1605. extern builtin_t *isbuiltin(char *);
  1606. extern void b_exec(char **), funcall(char **), b_dot(char **), b_builtin(char **);
  1607. extern char *which(char *, boolean);
  1608. SHAR_EOF
  1609. chmod 0644 builtins.h ||
  1610. echo 'restore of builtins.h failed'
  1611. Wc_c="`wc -c < 'builtins.h'`"
  1612. test 191 -eq "$Wc_c" ||
  1613.     echo 'builtins.h: original size 191, current size' "$Wc_c"
  1614. rm -f _shar_wnt_.tmp
  1615. fi
  1616. # ============= cfix.awk ==============
  1617. if test -f 'cfix.awk' -a X"$1" != X"-c"; then
  1618.     echo 'x - skipping cfix.awk (File already exists)'
  1619.     rm -f _shar_wnt_.tmp
  1620. else
  1621. > _shar_wnt_.tmp
  1622. echo 'x - extracting cfix.awk (Text)'
  1623. sed 's/^X//' << 'SHAR_EOF' > 'cfix.awk' &&
  1624. BEGIN                { Pending = 0; }
  1625. #
  1626. # Special cases.  There are too many, but....
  1627. #
  1628. $0 == "static int (*realgchar)(void);"    {
  1629. X                print "static int (*realgchar)();";
  1630. X                next;
  1631. X                }
  1632. $0 == "static void (*realugchar)(int);"    {
  1633. X                print "static void (*realugchar)();";
  1634. X                next;
  1635. X                }
  1636. $0 == "static void b_break(char **), b_cd(char **)," {
  1637. X                print "static void b_break(), b_cd(),";
  1638. X                next;
  1639. X                }
  1640. $0 == "\tb_echo(char **), b_eval(char **), b_exit(char **), b_limit(char **)," {
  1641. X                print "b_echo(), b_eval(), b_exit(), b_limit(),";
  1642. X                next;
  1643. X                }
  1644. $0 == "\tb_return(char **), b_shift(char **), b_umask(char **), b_wait(char **)," {
  1645. X                print "b_return(), b_shift(), b_umask(), b_wait(),";
  1646. X                next;
  1647. X                }
  1648. $0 == "\tb_whatis(char **);"    {
  1649. X                print "b_whatis();";
  1650. X                next;
  1651. X                }
  1652. $0 == "Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) {" {
  1653. X                print "Node *treecpy(s, alloc)";
  1654. X                printf "Node *s;\nvoid *(*alloc)();\n{\n";
  1655. X                next;
  1656. X                }
  1657. $0 == "\tvoid (*handler)(int);"    {
  1658. X                print "\tvoid (*handler)();";
  1659. X                next;
  1660. X                }
  1661. $0 == "\textern DIR *opendir(const char *);" {
  1662. X                print "#if 0";
  1663. X                print;
  1664. X                next;
  1665. X                }
  1666. $0 == "\textern int closedir(DIR *);" {
  1667. X                print;
  1668. X                print "#endif";
  1669. X                next;
  1670. X                }
  1671. $0 == "\textern int getopt(int, char **, char *);"    {
  1672. X                print "\textern int getopt();";
  1673. X                next;
  1674. X                }
  1675. $0 == "\tstatic void (*vectors[])(char *, List *, boolean) = {"    {
  1676. X                print "\tstatic void (*vectors[])() = {";
  1677. X                next;
  1678. X                }
  1679. $0 == "\t\tvoid (*handler)(int);"    {
  1680. X                print "\t\tvoid (*handler)();";
  1681. X                next;
  1682. X                }
  1683. $0 == "#include <stdarg.h>"    {
  1684. X                print "#include <varargs.h>";
  1685. X                next;
  1686. X                }
  1687. #
  1688. # General cases.
  1689. #
  1690. /^static .*\);$/        {
  1691. X                n = split($0, tmp1, "(");
  1692. X                if (n != 2) {
  1693. X                    print | "sh -c 'cat >&2'";
  1694. X                    print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
  1695. X                    next;
  1696. X                }
  1697. X                printf "%s();\n", tmp1[1];
  1698. X                next;
  1699. X                }
  1700. /^extern .*\);$/        {
  1701. X                n = split($0, tmp1, "(");
  1702. X                if (n != 2) {
  1703. X                    print | "sh -c 'cat >&2'";
  1704. X                    print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
  1705. X                    next;
  1706. X                }
  1707. X                printf "%s();\n", tmp1[1];
  1708. X                next;
  1709. X                }
  1710. /^[a-zA-Z_][a-zA-Z_0-9]*:/    {
  1711. X                print;
  1712. X                next;
  1713. X                }
  1714. /^[^ \t#][^(]*\([^)]*\.\.\.\).*{/ {
  1715. X                if (Pending != 0) {
  1716. X                    print "ERROR: Pending != 0 on function entry" | "sh -c 'cat >&2'";
  1717. X                    next;
  1718. X                }
  1719. X                n = split($0, tmp1, "(");
  1720. X                if (n != 2) {
  1721. X                    print | "sh -c 'cat >&2'";
  1722. X                    print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
  1723. X                    next;
  1724. X                }
  1725. X                n = split(tmp1[2], tmp2, ")");
  1726. X                if (n != 2) {
  1727. X                    print | "sh -c 'cat >&2'";
  1728. X                    print "ERROR with right parens: ", n | "sh -c 'cat >&2'";
  1729. X                    next;
  1730. X                }
  1731. X                printf "%s(va_alist)\nva_dcl\n{\n", tmp1[1];
  1732. X                nargs = split(tmp2[1], args, ",");
  1733. X                for (i = 1; i <= nargs; i++) {
  1734. X                    if (args[i] == "...") {
  1735. X                        if (i == nargs) {
  1736. X                            Pending = 1;
  1737. X                            continue;
  1738. X                        }
  1739. X                        print "ERROR: ... isn't last argument", $0 | "sh -c 'cat >&2'";
  1740. X                        next;
  1741. X                    }
  1742. X                    decls[i] = args[i] ";";
  1743. X                    t = args[i];
  1744. X                    for (;;) {
  1745. X                        n = split(t, varname, " ");
  1746. X                        if (n > 1) {
  1747. X                            t = varname[n];
  1748. X                            continue;
  1749. X                        }
  1750. X                        n = split(t, varname, "*");
  1751. X                        if (n > 1) {
  1752. X                            t = varname[n];
  1753. X                            continue;
  1754. X                        }
  1755. X                        break;
  1756. X                    }
  1757. X                    type = substr(args[i], 1, length(args[i]) - length(t));
  1758. X                    picks[i] = t " = va_arg(ap, " type ");"
  1759. X
  1760. X                }
  1761. X                nargs--;
  1762. X                next;
  1763. X                }
  1764. Pending == 1 && /va_list/    {
  1765. X                for (i = 1; i <= nargs; i++)
  1766. X                    print decls[i];
  1767. X                }
  1768. Pending == 1 && /va_start/    {
  1769. X                n = split($0, tmp1, ",");
  1770. X                if (n != 2) {
  1771. X                    print "ERROR: bad va_start format" | "sh -c 'cat >&2'";
  1772. X                    next;
  1773. X                }
  1774. X                printf "%s);\n", tmp1[1];
  1775. X                for (i = 1; i <= nargs; i++)
  1776. X                    print picks[i];
  1777. X                Pending = 0;
  1778. X                next;
  1779. X                }
  1780. /^[^ \t#][^(]*\([^)]*\).*{/    {
  1781. X                if (Pending != 0) {
  1782. X                    print "ERROR: Pending != 0 on function entry" | "sh -c 'cat >&2'";
  1783. X                    next;
  1784. X                }
  1785. X                n = split($0, tmp1, "(");
  1786. X                if (n != 2) {
  1787. X                    print | "sh -c 'cat >&2'";
  1788. X                    print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
  1789. X                    next;
  1790. X                }
  1791. X                n = split(tmp1[2], tmp2, ")");
  1792. X                if (n != 2) {
  1793. X                    print | "sh -c 'cat >&2'";
  1794. X                    print "ERROR with right parens: ", n | "sh -c 'cat >&2'";
  1795. X                    next;
  1796. X                }
  1797. #                if (tmp2[2] != " {") {
  1798. #                    print "ERROR with last component: `", tmp2[2], "'";
  1799. #                    next;
  1800. #                }
  1801. X                if (tmp2[1] ~ /^[ \t]*void[ \t]*$/ || tmp2[1] ~ /^[ \t]*$/) {
  1802. X                    # no arguments
  1803. X                    printf "%s() {\n\n", tmp1[1];
  1804. X                    next;
  1805. X                }
  1806. X                printf "%s(", tmp1[1];
  1807. X                needcomma = 0;
  1808. X                nargs = split(tmp2[1], args, ",");
  1809. X                for (i = 1; i <= nargs; i++) {
  1810. X                    if (args[i] == "...") {
  1811. X                        print "ERROR: ... shouldn't get here", $0 | "sh -c 'cat >&2'";
  1812. X                        next;
  1813. X                    }
  1814. X                    decls[i] = args[i] ";";
  1815. X                    if (needcomma)
  1816. X                        printf ", ";
  1817. X                    needcomma = 1;
  1818. X                    t = args[i];
  1819. X                    if (t ~ /\[\]$/)
  1820. X                        t = substr(t, 1, length(t) - 2);
  1821. X                    for (;;) {
  1822. X                        n = split(t, varname, " ");
  1823. X                        if (n > 1) {
  1824. X                            t = varname[n];
  1825. X                            continue;
  1826. X                        }
  1827. X                        n = split(t, varname, "*");
  1828. X                        if (n > 1) {
  1829. X                            t = varname[n];
  1830. X                            continue;
  1831. X                        }
  1832. X                        break;
  1833. X                    }
  1834. X                    printf "%s", varname[n];
  1835. X                }
  1836. X                print ")";
  1837. X                for (i = 1; i <= nargs; i++)
  1838. X                    print decls[i];
  1839. X                print "{";
  1840. X                next;
  1841. X                }
  1842. #
  1843. # If we didn't match at all, the line doesn't change.
  1844. #
  1845. X                { print; }
  1846. SHAR_EOF
  1847. chmod 0644 cfix.awk ||
  1848. echo 'restore of cfix.awk failed'
  1849. Wc_c="`wc -c < 'cfix.awk'`"
  1850. test 5252 -eq "$Wc_c" ||
  1851.     echo 'cfix.awk: original size 5252, current size' "$Wc_c"
  1852. rm -f _shar_wnt_.tmp
  1853. fi
  1854. # ============= config.h ==============
  1855. if test -f 'config.h' -a X"$1" != X"-c"; then
  1856.     echo 'x - skipping config.h (File already exists)'
  1857.     rm -f _shar_wnt_.tmp
  1858. else
  1859. > _shar_wnt_.tmp
  1860. echo 'x - extracting config.h (Text)'
  1861. sed 's/^X//' << 'SHAR_EOF' > 'config.h' &&
  1862. /*
  1863. X * Suggested settings for Sun, NeXT and sgi (machines here at TAMU):
  1864. X */
  1865. X
  1866. #ifdef NeXT
  1867. #define NODIRENT
  1868. #define    PROTECT_ENV
  1869. #define PROTECT_JOB
  1870. #define NOCMDARG
  1871. #endif
  1872. X
  1873. #ifdef sgi
  1874. #define NOSIGCLD
  1875. #define    PROTECT_ENV
  1876. #endif
  1877. X
  1878. #ifdef sun
  1879. #define PROTECT_ENV
  1880. #endif
  1881. X
  1882. /*
  1883. X * Suggested settings for HP300 running 4.3BSD-utah (DWS):
  1884. X */
  1885. X
  1886. #if defined(hp300) && !defined(hpux)
  1887. #define NODIRENT
  1888. #define NOCMDARG
  1889. #define DEFAULTINTERP "/bin/sh"
  1890. #define PROTECT_ENV
  1891. #endif
  1892. X
  1893. /*
  1894. X * Suggested settings for Ultrix
  1895. X */
  1896. X
  1897. #ifdef ultrix
  1898. #define PROTECT_ENV
  1899. #endif
  1900. SHAR_EOF
  1901. chmod 0644 config.h ||
  1902. echo 'restore of config.h failed'
  1903. Wc_c="`wc -c < 'config.h'`"
  1904. test 546 -eq "$Wc_c" ||
  1905.     echo 'config.h: original size 546, current size' "$Wc_c"
  1906. rm -f _shar_wnt_.tmp
  1907. fi
  1908. # ============= except.c ==============
  1909. if test -f 'except.c' -a X"$1" != X"-c"; then
  1910.     echo 'x - skipping except.c (File already exists)'
  1911.     rm -f _shar_wnt_.tmp
  1912. else
  1913. > _shar_wnt_.tmp
  1914. echo 'x - extracting except.c (Text)'
  1915. sed 's/^X//' << 'SHAR_EOF' > 'except.c' &&
  1916. #include "jbwrap.h"
  1917. #include <stdarg.h>
  1918. #include "rc.h"
  1919. #include "utils.h"
  1920. #include "except.h"
  1921. #include "status.h"
  1922. #include "hash.h"
  1923. #include "input.h"
  1924. #include "nalloc.h"
  1925. X
  1926. /*
  1927. X   a return goes back stack frames to the last return. A break does not. A signal
  1928. X   goes to the last interactive level.
  1929. */
  1930. X
  1931. static Estack *estack;
  1932. X
  1933. /* add an exception to the input stack. */
  1934. X
  1935. void except(enum except e, void *jb, Estack *ex) {
  1936. X    ex->prev = estack;
  1937. X    estack = ex;
  1938. X
  1939. X    switch (estack->e = e) {
  1940. X    case ARENA:
  1941. X        estack->b = newblock();
  1942. X        break;
  1943. X    case ERROR:
  1944. X    case BREAK:
  1945. X    case RETURN:
  1946. X        estack->interactive = interactive;
  1947. X        estack->jb = (jbwrap *) jb;
  1948. X        break;
  1949. X    case VARSTACK:
  1950. X        estack->name = (char *) jb;
  1951. X        break;
  1952. X    }
  1953. }
  1954. X
  1955. /* remove an exception, restore last interactive value */
  1956. X
  1957. void unexcept() {
  1958. X    if (estack->e == ERROR)
  1959. X        interactive = estack->interactive;
  1960. X    else if (estack->e == ARENA)
  1961. X        restoreblock(estack->b);
  1962. X    estack = estack->prev;
  1963. }
  1964. X
  1965. /*
  1966. X   Raise an exception. The rules are pretty complicated: you can return from a loop inside a
  1967. X   function, but you can't break from a function inside of a loop. On errors, rc_raise() goes back
  1968. X   to the LAST INTERACTIVE stack frame. If no such frame exists, then rc_raise() exits the shell.
  1969. X   This is what happens, say, when there is a syntax error in a noninteractive shell script. While
  1970. X   traversing the exception stack backwards, rc_raise() also removes input sources (closing
  1971. X   file-descriptors, etc.) and pops instances of $* that have been pushed onto the variable stack
  1972. X   (e.g., for a function call).
  1973. */
  1974. X
  1975. void rc_raise(enum except e) {
  1976. X    if (e == ERROR && rc_pid != getpid())
  1977. X            exit(1); /* child processes exit on an error/signal */
  1978. X
  1979. X    for (; estack != NULL; estack = estack->prev)
  1980. X        if (estack->e != e) {
  1981. X            if (e == BREAK && estack->e != ARENA)
  1982. X                rc_error("break outside of loop");
  1983. X            else if (e == RETURN && estack->e == ERROR) /* can return from loops inside functions */
  1984. X                rc_error("return outside of function");
  1985. X            if (estack->e == VARSTACK)
  1986. X                varrm(estack->name, TRUE);
  1987. X            else if (estack->e == ARENA)
  1988. X                restoreblock(estack->b);
  1989. X        } else {
  1990. X            if (e == ERROR && !estack->interactive) {
  1991. X                popinput();
  1992. X            } else {
  1993. X                jbwrap *j = estack->jb;
  1994. X
  1995. X                interactive = estack->interactive;
  1996. X                estack = estack->prev;
  1997. X                longjmp(j->j, 1);
  1998. X            }
  1999. X        }
  2000. X    rc_exit(1); /* top of exception stack */
  2001. }
  2002. SHAR_EOF
  2003. chmod 0644 except.c ||
  2004. echo 'restore of except.c failed'
  2005. Wc_c="`wc -c < 'except.c'`"
  2006. test 2339 -eq "$Wc_c" ||
  2007.     echo 'except.c: original size 2339, current size' "$Wc_c"
  2008. rm -f _shar_wnt_.tmp
  2009. fi
  2010. # ============= except.h ==============
  2011. if test -f 'except.h' -a X"$1" != X"-c"; then
  2012.     echo 'x - skipping except.h (File already exists)'
  2013.     rm -f _shar_wnt_.tmp
  2014. else
  2015. > _shar_wnt_.tmp
  2016. echo 'x - extracting except.h (Text)'
  2017. sed 's/^X//' << 'SHAR_EOF' > 'except.h' &&
  2018. enum except { ERROR, BREAK, RETURN, VARSTACK, ARENA };
  2019. typedef struct Estack Estack;
  2020. X
  2021. struct Estack {
  2022. X    enum except e;
  2023. X    boolean interactive;
  2024. X    jbwrap *jb;
  2025. X    Block *b;
  2026. X    char *name;
  2027. X    Estack *prev;
  2028. };
  2029. X
  2030. extern void rc_raise(enum except);
  2031. extern void except(enum except, void *, Estack *);
  2032. extern void unexcept(void);
  2033. SHAR_EOF
  2034. chmod 0644 except.h ||
  2035. echo 'restore of except.h failed'
  2036. Wc_c="`wc -c < 'except.h'`"
  2037. test 310 -eq "$Wc_c" ||
  2038.     echo 'except.h: original size 310, current size' "$Wc_c"
  2039. rm -f _shar_wnt_.tmp
  2040. fi
  2041. # ============= exec.c ==============
  2042. if test -f 'exec.c' -a X"$1" != X"-c"; then
  2043.     echo 'x - skipping exec.c (File already exists)'
  2044.     rm -f _shar_wnt_.tmp
  2045. else
  2046. > _shar_wnt_.tmp
  2047. echo 'x - extracting exec.c (Text)'
  2048. sed 's/^X//' << 'SHAR_EOF' > 'exec.c' &&
  2049. /*
  2050. X   exec.c: exec() takes an argument list and does the appropriate thing
  2051. X   (calls a builtin, calls a function, etc.)
  2052. */
  2053. X
  2054. #include <signal.h>
  2055. #include <errno.h>
  2056. #include "rc.h"
  2057. #include "utils.h"
  2058. #include "exec.h"
  2059. #include "status.h"
  2060. #include "hash.h"
  2061. #include "builtins.h"
  2062. #include "footobar.h"
  2063. #include "jbwrap.h"
  2064. #include "except.h"
  2065. #include "redir.h"
  2066. #include "wait.h"
  2067. X
  2068. void exec(List *s, boolean parent) {
  2069. X    char **av, **ev;
  2070. X    int pid, stat;
  2071. X    builtin_t *b;
  2072. X    char *path = NULL;
  2073. X    void (*handler)(int);
  2074. X    boolean forked, saw_exec, saw_builtin;
  2075. X
  2076. X    av = list2array(s, dashex);
  2077. X    ev = makeenv();
  2078. X    saw_builtin = saw_exec = FALSE;
  2079. X
  2080. X    do {
  2081. X        if (*av == NULL    || isabsolute(*av))
  2082. X            b = NULL;
  2083. X        else if (!saw_builtin && fnlookup(*av) != NULL)
  2084. X            b = funcall;
  2085. X        else
  2086. X            b = isbuiltin(*av);
  2087. X
  2088. X        saw_builtin = FALSE; /* a builtin applies only to the immmediately following command, e.g., builtin exec echo hi */
  2089. X
  2090. X        if (b == b_exec) {
  2091. X            av++;
  2092. X            saw_exec = TRUE;
  2093. X            parent = FALSE;
  2094. X        } else if (b == b_builtin) {
  2095. X            av++;
  2096. X            saw_builtin = TRUE;
  2097. X        }
  2098. X    } while (b == b_exec || b == b_builtin);
  2099. X
  2100. X    if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */
  2101. X        doredirs();
  2102. X        return;
  2103. X    }
  2104. X
  2105. X    if (b == NULL) {
  2106. X        path = which(*av, TRUE);
  2107. X        if (path == NULL && *av != NULL) { /* perform null commands for redirections */
  2108. X            set(FALSE);
  2109. X            redirq = NULL;
  2110. X            empty_fifoq();
  2111. X            if (parent)
  2112. X                return;
  2113. X            rc_exit(1);
  2114. X        }
  2115. X    }
  2116. X
  2117. X    /* if parent & the redirq is nonnull, builtin or not it has to fork. */
  2118. X
  2119. X    if (parent && (b == NULL || redirq != NULL)) {
  2120. X        pid = rc_fork();
  2121. X        forked = TRUE;
  2122. X    } else {
  2123. X        pid = 0;
  2124. X        forked = FALSE;
  2125. X    }
  2126. X
  2127. X    switch (pid) {
  2128. X    case -1:
  2129. X        uerror("fork");
  2130. X        rc_error(NULL);
  2131. X        /* NOTREACHED */
  2132. X    case 0:
  2133. X        if (forked)
  2134. X            setsigdefaults();
  2135. X        doredirs();
  2136. X
  2137. X        /* null commands performed for redirections */
  2138. X        if (*av == NULL || b != NULL) {
  2139. X            if (b != NULL)
  2140. X                b(av);
  2141. X            empty_fifoq();
  2142. X            if (!forked && parent)
  2143. X                return;
  2144. X            rc_exit(getstatus());
  2145. X        }
  2146. #ifdef NOEXECVE
  2147. X        my_execve(path, (const char **) av, (const char **) ev); /* bogus, huh? */
  2148. #else
  2149. X        execve(path, (const char **) av, (const char **) ev);
  2150. #endif
  2151. #ifdef DEFAULTINTERP
  2152. X        if (errno == ENOEXEC) {
  2153. X            *av = path;
  2154. X            *--av = DEFAULTINTERP;
  2155. X            execve(*av, (const char **) av, (const char **) ev);
  2156. X        }
  2157. #endif
  2158. X        uerror(*av);
  2159. X        rc_exit(1);
  2160. X        /* NOTREACHED */
  2161. X    default:
  2162. X        if ((handler = signal(SIGINT, SIG_IGN)) != sig)
  2163. X            signal(SIGINT, handler); /* don't ignore interrupts in noninteractive mode */
  2164. X        rc_wait4(pid, &stat);
  2165. X        signal(SIGINT, handler);
  2166. X        redirq = NULL;
  2167. X        empty_fifoq();
  2168. X        setstatus(stat);
  2169. X        if (stat == SIGINT || stat == SIGQUIT) /* interrupted? let the handler deal with it. */
  2170. X            rc_raise(ERROR);
  2171. X    }
  2172. }
  2173. SHAR_EOF
  2174. chmod 0644 exec.c ||
  2175. echo 'restore of exec.c failed'
  2176. Wc_c="`wc -c < 'exec.c'`"
  2177. test 2671 -eq "$Wc_c" ||
  2178.     echo 'exec.c: original size 2671, current size' "$Wc_c"
  2179. rm -f _shar_wnt_.tmp
  2180. fi
  2181. # ============= exec.h ==============
  2182. if test -f 'exec.h' -a X"$1" != X"-c"; then
  2183.     echo 'x - skipping exec.h (File already exists)'
  2184.     rm -f _shar_wnt_.tmp
  2185. else
  2186. > _shar_wnt_.tmp
  2187. echo 'x - extracting exec.h (Text)'
  2188. sed 's/^X//' << 'SHAR_EOF' > 'exec.h' &&
  2189. struct Rq {
  2190. X    Node *r;
  2191. X    struct Rq *n;
  2192. };
  2193. X
  2194. extern void exec(List *, boolean);
  2195. extern void doredirs(void);
  2196. SHAR_EOF
  2197. chmod 0644 exec.h ||
  2198. echo 'restore of exec.h failed'
  2199. Wc_c="`wc -c < 'exec.h'`"
  2200. test 104 -eq "$Wc_c" ||
  2201.     echo 'exec.h: original size 104, current size' "$Wc_c"
  2202. rm -f _shar_wnt_.tmp
  2203. fi
  2204. # ============= execve.c ==============
  2205. if test -f 'execve.c' -a X"$1" != X"-c"; then
  2206.     echo 'x - skipping execve.c (File already exists)'
  2207.     rm -f _shar_wnt_.tmp
  2208. else
  2209. > _shar_wnt_.tmp
  2210. echo 'x - extracting execve.c (Text)'
  2211. sed 's/^X//' << 'SHAR_EOF' > 'execve.c' &&
  2212. /* execve.c: an execve() for geriatric unices without #! */
  2213. SHAR_EOF
  2214. true || echo 'restore of execve.c failed'
  2215. fi
  2216. echo 'End of  part 1'
  2217. echo 'File execve.c is continued in part 2'
  2218. echo 2 > _shar_seq_.tmp
  2219. exit 0
  2220. exit 0 # Just in case...
  2221. -- 
  2222. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2223. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2224. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2225. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2226.